package nl.infodation.emr.pricingservice.valuesimporter;


import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import nl.infodation.emr.pricingservice.exception.RmeException;

public final class CSVFileReader {

	public static final String FILE_ERRORS = "The file does not exist, please select a csv file and try again.";
	public static final String PARSE_ERRORS = "Error happen while reading the file, please try again.";
	public static final String FILE_RELEASE_ERRORS = "Could not release the input file.";
	private transient CSVFormat format = null;
	private transient BufferedReader	reader				= null;

	public CSVFileReader(final File file) throws RmeException {
		try {
			final InputStream stream = new FileInputStream(file);
			reader = new BufferedReader(new InputStreamReader(stream));
			this.format = new CSVFormat();
		} catch (FileNotFoundException ex){
			throw new RmeException(FILE_ERRORS, ex);
		}
	}

	
	/**
	 * read next char
	 */
	private int read() throws IOException {
		return reader.read();
	}


	/**
	 * Parse a CSV string to data
	 * 
	 * @return a simple CSV object with data. null if the raw data cannot be
	 *         parse
	 * @throw PortfolioException
	 */
	private CSVLine readLine() throws RmeException {
		final StringBuilder element = new StringBuilder();
		CSVLine currentLine = null; 
		try {
			int currentInt = -1;
			while ((currentInt = read()) != -1) {
				if (currentLine == null) {
					currentLine = CSVLine.getInstance();
				}
				if (format.isIgnored((char) currentInt)) {
					continue; // just ignore
				}else if (currentInt == format.getLineTerminator()) {
					currentLine.add(element.toString());
					return currentLine;
				} else if (currentInt == format.getFieldDelimiter()) {
					element.append('-');
					currentLine.add(element.toString());
					element.setLength(0); // reset current element
					continue;
				}
				// otherwise, it's a normal character, just add
				element.append((char) currentInt);
				
			}// continue while

			// add content for current line
			if (element != null && currentLine != null) {
				currentLine.add(element.toString());
			}
		} catch (IOException ex) {
			throw new RmeException(PARSE_ERRORS, ex);
		}
		return currentLine;
	}


	/**
	 * Parse a CSV stream to data
	 * 
	 * @param stream
	 *            InputStream
	 * @return a simple CSV object with data. null if the raw data cannot be
	 *         parse
	 */
	private CSVFile parse() throws RmeException {
		final CSVFile file = new CSVFile();
		CSVLine line = null;
		do {
			line = readLine();
			file.append(line);
		} while (line != null);
		return file;
	}

	/**
	 * Parse file content to CSV
	 * 
	 * @param path
	 * @return CSVFile
	 * @throws RmeException 
	 */
	public CSVFile parseFile() throws RmeException {
		try {
			return parse();
		}finally{
			if(null != reader){
				try {
					reader.close();
				} catch (IOException ex) {
					throw new RmeException(FILE_RELEASE_ERRORS, ex);
				}
			}
		}
	}

}
